package com.wits.platform.dao.impl;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TemporalType;

import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Component;

import com.wits.platform.common.utils.PageUtil;
import com.wits.platform.dao.custom.BaseDaoCustom;
import com.wits.platform.web.mvc.PageParam;

@Component
public class BaseDaoImpl<T, ID extends Serializable> implements BaseDaoCustom<T,ID>{



	@PersistenceContext
	protected EntityManager em;
	
	@Override
	public void updateField(Class<T> entityClass, Serializable Id, String fieldName,Object fieldValue) throws Exception {
		T obj = em.find(entityClass, Id);
		Field field = obj.getClass().getDeclaredField(fieldName);
		field.setAccessible(true);
		field.set(obj, fieldValue);
		em.persist(obj);
	}
	
	
	public void updateField(Class<T> entityClass, Serializable Id, Map<String,Object> map) throws Exception {
		T obj = em.find(entityClass, Id);
		Field field=null;
		String fieldName=null;
		for(Iterator<String> key=map.keySet().iterator();key.hasNext();){
			fieldName=key.next();
			field=entityClass.getDeclaredField(fieldName);
			field.setAccessible(true);
			field.set(obj,map.get(fieldName));
		}
		em.persist(obj);
	}
	
	
	
    @SuppressWarnings({ "unchecked", "hiding" })
	protected <T> T uniqueByNative(String sql,Object... paramlist) {
        Query query = em.createNativeQuery(sql);
        setParameters(query, paramlist);
        return (T) query.setMaxResults(1).getSingleResult();
    }
    
    @Override
	public int executeUpdateByNative(String sql,Object...paramList){
		Query query=em.createNativeQuery(sql);
		setParameters(query, paramList);
		return query.executeUpdate();
	}
	
    @Override
	public int executeUpdate(String hql,Object...paramList){
		Query query=em.createQuery(hql);
		setParameters(query, paramList);
		return query.executeUpdate();
	}
	
    
    protected void setParameters(Query query, Object[] paramList) {
        if (paramList != null) {
            for (int i = 0; i < paramList.length; i++) {
                if(paramList[i] instanceof Date) {
                	query.setParameter(i+1, (Date)paramList[i], TemporalType.DATE);
                } else {
                    query.setParameter(i+1, paramList[i]);
                }
            }
        }
    }
    
    
    
	@SuppressWarnings("unchecked")
	public Page<T> findPageByNative(Class<T> resultClass,String sql,PageParam pageParam,Object...params){
        Query query=em.createNativeQuery(sql, resultClass);
        setParameters(query, params);
		query.setFirstResult(PageUtil.getPageStart(pageParam.getPageNum(),pageParam.getNumPerPage()));
		query.setMaxResults(pageParam.getNumPerPage());
		String totalSql =PageUtil.getCountQuery(sql);
		Number total = uniqueByNative(totalSql,params);
		List<T> content=query.getResultList();
		Page<T> page=new PageImpl<T>(content,null,total.longValue());
		return page;
	}
	
	@SuppressWarnings("unchecked")
	public  List<T>  findByNative(Class<T> resultClass,String sql,Object...params){
        Query query=em.createNativeQuery(sql, resultClass);
        setParameters(query, params);
		return (List<T>)query.getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findByNative(String resultSetMapping,String sql,Object...params){
        Query query=em.createNativeQuery(sql,resultSetMapping);
        setParameters(query, params);
		return query.getResultList();
	}
	
	
	@SuppressWarnings("unchecked")
	public List<T> find(Class<T> entityClass,String hql,Object...params){
		Query query=em.createQuery(hql,entityClass);
		setParameters(query, params);
		return query.getResultList();
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<Map> findByHibernateNative(String sql,Object...params){
		Session session=(Session)em.getDelegate();
		SQLQuery query=session.createSQLQuery(sql);
		query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        setParameters(query, params);
		return query.list();
	}
	
	
	@SuppressWarnings({"rawtypes" })
	public List findByHibernateNative(Class dtoClass,String sql,Object...params){
		Session session=(Session)em.getDelegate();
		SQLQuery query=session.createSQLQuery(sql);
		query.setResultTransformer(Transformers.aliasToBean(dtoClass));
        setParameters(query, params);
		return query.list();
	}
	
    protected void setParameters(SQLQuery query, Object[] paramList) {
        if (paramList != null) {
            for (int i = 0; i < paramList.length; i++) {
            	 query.setParameter(i, paramList[i]);
            }
        } 
    }


	@Override
	public void clear() {
		this.em.clear();
	}


	@Override
	public void flush() {
		this.em.flush();
	}
}
